/*
 * Copyright 2025 The JA-SIG Collaborative. All rights reserved.
 * distributed with this file and available online at
 */
package com.lap.auth.application.region;

import com.lap.auth.application.region.assembler.RegionAssembler;
import com.lap.auth.application.region.command.BatchCreateRegionCmd;
import com.lap.auth.application.region.command.BatchUpdateRegionCmd;
import com.lap.auth.application.region.command.UpdateRegionCmd;
import com.lap.auth.application.region.dto.GetRegionByIdsQuery;
import com.lap.auth.application.region.dto.RegionDto;
import com.lap.auth.application.region.dto.RegionOptionDto;
import com.lap.auth.application.region.dto.RegionViewDto;
import com.lap.auth.domain.region.Region;
import com.lap.auth.domain.region.repository.RegionRepository;
import com.lap.auth.domain.region.service.RegionValidator;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 区域应用服务层
 *
 * <ol>
 *   <li>不做业务规则，只做技术规则（加密/解密是技术实现，业务不关注）
 *   <li>取数，赋值，对象转换在这层执行
 *   <li>命名有规范，动词+领域名字
 *   <li>如查询比较多，建议分开领域QueryAppService,如:分页查询，分页查询返回关联字段
 * </ol>
 */
@RequiredArgsConstructor
@Service
public class RegionAppService {

  private final RegionAssembler regionAssembler;
  private final RegionValidator validator;
  private final RegionRepository regionRepository;

  public List<RegionDto> getRegionTree() {
    List<Region> all = regionRepository.findAll();
    List<RegionDto> dtoList = regionAssembler.toDtoList(all);
    return regionAssembler.convertToTree(dtoList);
  }

  public RegionViewDto queryRegions(Integer parentId) {
    Optional<Region> optional = regionRepository.findById(parentId);
    RegionDto parent = optional.map(regionAssembler::toDto).orElse(null);
    List<Region> list = regionRepository.findByPid(parentId);
    return new RegionViewDto(parent, regionAssembler.toDtoList(list));
  }

  public List<RegionOptionDto> queryRegionsByIds(GetRegionByIdsQuery query) {
    List<Region> list = regionRepository.findByIds(query.getIdSet());
    return regionAssembler.toOptionDtoList(list);
  }

  @Transactional(rollbackFor = Exception.class)
  public void batchCreateRegions(BatchCreateRegionCmd cmd) {
    Region region = regionAssembler.toDomain(cmd);
    region.initPidPath(() -> regionRepository.findById(region.getParentId()));
    List<Region> children = regionAssembler.toChildrenDomains(region, cmd.getChildren());
    regionRepository.saveAll(region, children);
  }

  @Transactional(rollbackFor = Exception.class)
  public int updateRegion(Integer id, UpdateRegionCmd cmd) {
    validator.assertRegionExists(id);
    Region region = regionAssembler.toDomain(id, cmd);
    // TODO 修复数据使用
    if (region.getParentId() != null) {
      region.initPidPath(() -> regionRepository.findById(region.getParentId()));
    }
    return regionRepository.save(region);
  }

  public void batchUpdateRegions(Integer id, BatchUpdateRegionCmd cmd) {
    validator.assertRegionExists(id);
    Region region = regionAssembler.toDomain(id, cmd);
    // TODO 修复数据使用
    if (region.getParentId() != null) {
      region.initPidPath(() -> regionRepository.findById(region.getParentId()));
    }
    List<Region> children = regionAssembler.toChildrenDomains(region, cmd.getChildren());
    regionRepository.saveAll(region, children);
  }

  public Integer deleteRegion(Integer id) {
    Region region = validator.assertRegionExists(id);
    List<Region> children = regionRepository.findByPid(id);
    region.canDelete(children);
    return regionRepository.deleteById(id);
  }
}
